package geppetto.phraseTable.phrase;


import geppetto.cat.common.StaticTools;
import geppetto.cat.corpus.BilingualCorpus;
import geppetto.phraseHMM.WordTrie;
import geppetto.phraseHMM.phraseExtraction.extractedphrase.ExtractedPhrasePairData;
import geppetto.phraseHMM.phraseExtraction.extractedphrase.ExtractedPhrasePairDataManager;
import geppetto.phraseHMM.phraseExtraction.extractedphrase.data.ExtractedSentenceData;
import geppetto.phraseTable.PrintSpecification;
import geppetto.phraseTable.phrase.feature.CompositeFeature;
import geppetto.reordering.AbstractReorderingCalculator;
import geppetto.reordering.ReorderingInfo;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;



public class Phrase {
	public int _sourcePhraseID;
	public int _targetPhraseID;
	public int sourceLen;
	public int targetLen;
	public double _counts;
	public CompositeFeature _features = new CompositeFeature();
	protected ExtractedPhrasePairData[] _data;
	public ReorderingInfo _reorderingInfo;
	public boolean pruned = false;

	public Phrase(int sourcePhraseId, int targetPhraseId, double counts) {
		_sourcePhraseID = sourcePhraseId;
		_targetPhraseID = targetPhraseId;
		_counts = counts;
		_data = new ExtractedPhrasePairData[ExtractedPhrasePairDataManager.getDataElementSize()];
	}
	
	public Phrase(int sourcePhraseId, int targetPhraseId, double counts, ReorderingInfo reorderingInfo) {
		this(sourcePhraseId, targetPhraseId, counts);
		_reorderingInfo = reorderingInfo;
	}
	
	public boolean equals(Object p){
		if (!(p instanceof Phrase)) {
			return false;
		}
		Phrase p1 = (Phrase)p;
		return _sourcePhraseID == p1._sourcePhraseID && _targetPhraseID == p1._targetPhraseID && StaticTools.compareDoubles(_counts,p1._counts); 
	}
	
	public double getCounts(){
		return _counts;
	}
	
	public void setCounts(double counts){
		_counts = counts;
	}	
	
	public void addCounts(double counts){
		_counts += counts;
	}

	// Null phrase
	public Phrase(int targetPhraseId, double counts) {
		this(-1, targetPhraseId, counts);
	}

	public String stringRep(BilingualCorpus corpus, WordTrie sourcePhrases,
			WordTrie foreignPhrases) {
		String phrase = "";
		String sourceS  = "";
		String targetS = "";
		if (_sourcePhraseID != -1) {
			int[] source = sourcePhrases.getPhraseIndexesById(_sourcePhraseID);
			for (int i = 0; i < source.length; i++) {
				sourceS += corpus.getSourceWordById(source[i]) + " ";
			}
			sourceS += " " + _sourcePhraseID + " ||  ";
		} else {
			sourceS += "null " + " ||  ";
		}
		int[] target = foreignPhrases.getPhraseIndexesById(_targetPhraseID);
		for (int i = 0; i < target.length; i++) {
			targetS += corpus.getForeignWordById(target[i]) + " ";
		}
		targetS += " " + _targetPhraseID + "|| " ;
		phrase +=  targetS + sourceS +  " : " + _counts;
		return phrase;
	}
	
	public String stringSimpleRep(BilingualCorpus corpus, WordTrie sourcePhrases,
			WordTrie foreignPhrases) {
		String phrase = "";
		String sourceS  = "";
		String targetS = "";
		if (_sourcePhraseID != -1) {
			int[] source = sourcePhrases.getPhraseIndexesById(_sourcePhraseID);
			for (int i = 0; i < source.length; i++) {
				sourceS += corpus.getSourceWordById(source[i]) + " ";
			}
			sourceS += "\t" ;
		} else {
			sourceS += "null " + "\t";
		}
		int[] target = foreignPhrases.getPhraseIndexesById(_targetPhraseID);
		for (int i = 0; i < target.length; i++) {
			targetS += corpus.getForeignWordById(target[i]) + " ";
		}
		targetS = targetS + "\t";
		phrase +=  targetS + sourceS +  "\t" + _counts + "\t";
		return phrase;
	}
	
	public String stringMosesRep(BilingualCorpus corpus, WordTrie sourcePhrases,
			WordTrie foreignPhrases, PrintSpecification spec) {
		String sourceS  = getSourceString(corpus, sourcePhrases, foreignPhrases);
		String targetS = getTargetString(corpus, sourcePhrases, foreignPhrases);
		String phrase = spec.getSourcePrinter().getStringToPrint(sourceS) + " ||| " + spec.getTargetPrinter().getStringToPrint(targetS) +  " ||| " + getFeaturesMoses();
		return phrase;
	}
	
	public String stringMosesPhraseExtraction(BilingualCorpus corpus, WordTrie sourcePhrases,
			WordTrie foreignPhrases, AbstractReorderingCalculator reoCalc){
		String sourceS  = getSourceString(corpus, sourcePhrases, foreignPhrases);
		String targetS = getTargetString(corpus, sourcePhrases, foreignPhrases);
		String phrase = sourceS + " ||| " + targetS +  " ||| " + 
		reoCalc.getStringFromCode(get_reorderingInfo().getPreviousWordOrientationCounts().keys()[0]) + " "
		+ reoCalc.getStringFromCode(get_reorderingInfo().getNextWordOrientationCounts().keys()[0]);
		return phrase;
	}
	
	public String stringMosesReordering(BilingualCorpus corpus, WordTrie sourcePhrases,
			WordTrie foreignPhrases, double[] reordPrevValues, double[] reordNextValues){
		String sourceS  = getSourceString(corpus, sourcePhrases, foreignPhrases);
		String targetS = getTargetString(corpus, sourcePhrases, foreignPhrases);
		String reorderingParameters = "";
		for (double v : reordPrevValues){
			reorderingParameters += convertDoubleToMosesFormat(v) + " ";
		}
		for (double v : reordNextValues){
			reorderingParameters += convertDoubleToMosesFormat(v) + " ";
		}
		return sourceS + " ||| " + targetS +  " ||| " + reorderingParameters.substring(0, reorderingParameters.length() - 1);
	}
	
	public static String getSourceString(BilingualCorpus corpus, WordTrie sourcePhrases,
			WordTrie foreignPhrases, int sourceId) {
		if (sourceId != -1) {
			int[] source = sourcePhrases.getPhraseIndexesById(sourceId);
			return getSourceString(corpus, source);
		} else {
			return "null";
		}
	}
	
	public static String getSourceString(BilingualCorpus corpus, int[] source) {
		String sourceS = "";
		for (int i = 0; i < source.length; i++) {
			sourceS += corpus.getSourceWordById(source[i]);
			if(i!=source.length-1){sourceS+= " ";}
		}
		return sourceS;
	}
	
	public String getSourceString(BilingualCorpus corpus, WordTrie sourcePhrases,
			WordTrie foreignPhrases) {
		return getSourceString(corpus, sourcePhrases, foreignPhrases, _sourcePhraseID);
	}
	
	public static String getTargetString(BilingualCorpus corpus, WordTrie sourcePhrases,
			WordTrie foreignPhrases, int targetId) {
		int[] target = foreignPhrases.getPhraseIndexesById(targetId);
		return getTargetString(corpus, target);
	}
	
	public static String getTargetString(BilingualCorpus corpus, int[] target) {
		String targetS = "";
		for (int i = 0; i < target.length; i++) {
			targetS += corpus.getForeignWordById(target[i]);
			if(i!=target.length-1){targetS+= " ";}
		}
		return targetS;
	}
	
	public String getTargetString(BilingualCorpus corpus, WordTrie sourcePhrases,
			WordTrie foreignPhrases) {
		return getTargetString(corpus, sourcePhrases, foreignPhrases, _targetPhraseID);
	}
	
	private String convertDoubleToMosesFormat(double n){
		BigDecimal bd = new BigDecimal(n);
		bd = bd.setScale(6, BigDecimal.ROUND_HALF_UP);
		return bd.toString();
	}
	
	public void toSaveFormat(DataOutputStream out) throws IOException{
		out.writeInt(_sourcePhraseID);
		out.writeInt(_targetPhraseID);
	}
	
	public static Phrase fromSaveFormat(DataInputStream in) throws IOException{
		int sourcePhraseId = in.readInt();
		int targetPhraseId = in.readInt();
		double prob = in.readDouble();
		Phrase p;
		if(sourcePhraseId == -1){
			p = new Phrase(targetPhraseId,prob);
		}else{
			p = new Phrase(sourcePhraseId,targetPhraseId,prob);
		}
		return p;
	}

	public ReorderingInfo get_reorderingInfo() {
		return _reorderingInfo;
	}

	public void set_reorderingInfo(ReorderingInfo info) {
		_reorderingInfo = info;
	}
	
	public String toString(){
		String phrase = _sourcePhraseID + " ||| " + _targetPhraseID +  " ||| " + 
		_features.toMosesFormat();
		return phrase;
	}
	
	public String getFeaturesMoses(){
		return _features.toMosesFormat();
	}

	public int getSourceLen() {
		return sourceLen;
	}

	public void setSourceLen(int sourceLen) {
		this.sourceLen = sourceLen;
	}

	public int getTargetLen() {
		return targetLen;
	}

	public void setTargetLen(int targetLen) {
		this.targetLen = targetLen;
	}

	public ExtractedPhrasePairData[] get_data() {
		return _data;
	}

	public ExtractedPhrasePairData getData(String name){
		return _data[ExtractedPhrasePairDataManager.getDataOrder(name)];
	}
	
	public void setData(String name, ExtractedPhrasePairData value){
		_data[ExtractedPhrasePairDataManager.getDataOrder(name)] = value;
	}

	public boolean isPruned() {
		return pruned;
	}

	public void setPruned(boolean pruned) {
		this.pruned = pruned;
	}

	public void set_data(HashMap<String, ExtractedPhrasePairData> hashMap) {
		for(String dataName : hashMap.keySet()){
			setData(dataName, hashMap.get(dataName));
		}
	}
	

}
